<template>
	<div class="xh-form" ref="form">
		<el-form
			ref="crmForm"
			:model="elFormModel"
			label-position="top"
			class="crm-create-box"
			:style="[bindStyle]"
			:size="size"
		>
			<template v-for="(group, index) in this.crmConfigs">
				<div class="xh-title" :key="index" v-if="group.title">
					{{ group.getTitle ? group.getTitle(group, crmConfigs) : group.title }}
				</div>
				<el-form-item
					v-for="(item, index) in group.fields"
					:key="item.key"
					:prop="item.key"
					:rules="crmRules[item.key]"
					class="crm-create-item"
					:class="[
						isElItemBlock
							? 'crm-create-item--block'
							: item.showblock
							? 'crm-create-item--block'
							: 'crm-create-item--half',
						size === 'mini' ? 'crm-create-item--mini' : '',
						'crm-create-item-' + item.data.formType
					]"
					v-show="index < visibleLimit"
				>
					<div slot="label" style="display: inline-block">
						<div
							style="
								margin: 6px 0;
								font-size: 14px;
								word-wrap: break-word;
								word-break: break-all;
							"
						>
							{{ item.data.name }}
							<span style="color: #999" v-if="item.data.inputTips">
								({{ item.data.inputTips }})
							</span>
						</div>
					</div>
					<!-- 员工 和部门 为多选（radio=false）  relation 相关保单订单使用-->
					<xh-element
						:value="item.value"
						:index="index"
						:item="item"
						:type="item.data.formType"
						:sub-type="item.data.fieldType"
						:query="item.query"
						:relation="item.relation"
						:radio="item.radio"
						:disabled="item.disabled"
						:disabledRows="item.data.disabledRows || []"
						:filterable="item.filterable"
						:allow-create="item.allowCreate"
						:multiple="item.multiple"
						:action="{ type: 'save' }"
						:params="item.data.params"
						:counts="item.counts"
						@value-change="valueChange"
					/>
				</el-form-item>
				<slot name="append"></slot>
			</template>
		</el-form>
	</div>
</template>

<script>
import {
	regexIsCRMNumber,
	regexIsCRMPassword,
	regexIsCRMMoneyNumber,
	regexIsCRMMobile,
	regexIsCRMEmail,
	objDeepCopy
} from '@/utils'
import request from '@/api/fetch'
const XhElement = () => import('./XhElement')
import decorateField from './formFn/decorateField'
function setlink(link) {
	link.forEach((item) => {
		if (link.filter((_item) => _item.fieldName === item.fieldName).length > 1) {
			item.fieldName = Math.random() + ''
		}
	})
}
import { debounce } from 'throttle-debounce'
const sendCalenderRequest = debounce(500, (url, data, callback) => {
	return request({
		url,
		method: 'post',
		data,
		headers: {
			'Content-Type': 'application/json'
		}
	}).then((res) => {
		callback(res)
	})
})
export default {
	components: { XhElement },
	props: {
		// 表单配置
		configs: {
			type: Array,
			required: true
		},
		// 添加字段前
		beforeAddFields: Function,
		// 添加字段组前
		beforeAddGroup: Function,
		// 纵向间隔
		columnGap: String,

		size: {
			type: String,
			default: 'medium'
		},
		// 限制展示几个字段
		visibleLimit: {
			type: Number,
			default: Infinity
		}
	},
	provide() {
		return { XhForm: this }
	},
	data() {
		return {
			crmConfigs: [],
			crmRules: {},
			isElItemBlock: !1
		}
	},
	created() {
		const { configs } = this
		this.initForm(configs)
	},
	mounted() {
		this.isElItemBlock = this.$refs.form.offsetWidth < 350
	},
	watch: {
		configs: {
			handler(val) {
				this.crmConfigs = []
				this.initForm(val)
			}
		}
	},
	methods: {
		initForm(configs) {
			var _configs = this.initConfigs(objDeepCopy(configs))
			this.crmConfigs.push(...this.initFields(_configs))
			this.initRules(_configs)
		},
		initConfigs(configs) {
			for (let index = 0; index < configs.length; index++) {
				try {
					const fields = configs[index].fields
					let loopFields = fields
					let newFields = []
					while (loopFields.length) {
						let _loop = []
						loopFields.forEach((field) => {
							const maybeLink = ['select', 'business_status', 'brand'].includes(
								field.formType
							)
							if (maybeLink && field.value) {
								const option = field.setting.find(
									(option) => option.value === field.value
								)
								if (option?.link) {
									const addItems = this.useBeforeAddFields(option.link)
									_loop.push(...addItems)
									newFields.push(...addItems)
								}
							}
						})
						loopFields = _loop
					}
					fields.push(...newFields)
				} catch (e) {
					console.error(e, configs[index])
				}
			}
			var _configs = []
			configs
				.map((config) => config.fields)
				.flat()
				.forEach((field) => {
					const maybeGroup = ['select', 'business_status', 'brand'].includes(
						field.formType
					)
					if (maybeGroup && field.value) {
						const option = field.setting.find(
							(option) => option.value === field.value
						)
						if (option?.group) {
							option.group.forEach((g) => (g.fields = g.source))
							const group = this.beforeAddGroup?.(option.group) || option.group
							_configs.push(...group)
						}
					}
				})
			if (_configs.length) {
				this.initConfigs(_configs)
				configs.push(..._configs)
			}
			return configs
		},
		initFields(configs) {
			return configs.map((config) => {
				var fields = config.fields.map((field) => decorateField(field))
				return { ...config, fields }
			})
		},
		initRules(configs) {
			const sourceFields = configs.map((v) => v.fields).flat()
			this.getRules(sourceFields)
		},
		getRules(fields) {
			fields.forEach((field) => {
				this.crmRules[field.key || field.fieldName] =
					this.crmRules[field.key || field.fieldName] || []
				const sourceField = field.key ? field.data : field
				const rule = this.getRule(sourceField)
				this.crmRules[field.key || field.fieldName].push(...rule)
			})
		},
		getRule(field) {
			const item = field
			const tempList = []
			// 验证必填
			if (item.isNull == 1) {
				if (item.formType == 'category') {
					tempList.push({
						required: true,
						message: item.name + '不能为空',
						trigger: []
					})
				} else {
					tempList.push({
						required: true,
						message: item.name + '不能为空',
						trigger: []
					})
				}
			}

			// 验证唯一
			if (item.isUnique == 1) {
				const validateUnique = (rule, value, callback) => {
					if (!value && rule.item.isNull == 0) {
						callback()
					} else {
						const validatesParams = {}
						validatesParams.name = item.name
						validatesParams.val = value
						validatesParams.types = crmTypeModel[this.crmType]
						if (this.action.type == 'update') {
							validatesParams.id = this.action.id
						}
						filedValidates(validatesParams)
							.then((res) => {
								callback()
							})
							.catch((error) => {
								callback(new Error(error.error ? error.error : '验证出错'))
							})
					}
				}
				tempList.push({
					validator: validateUnique,
					item: item,
					trigger: ['change']
				})
			}

			// 特殊字符
			if (item.formType == 'number') {
				const validateCRMNumber = (rule, value, callback) => {
					if (!value || value == '' || regexIsCRMNumber(value)) {
						callback()
					} else {
						callback(new Error('数字的整数部分须少于12位，小数部分须少于4位'))
					}
				}
				tempList.push({
					validator: validateCRMNumber,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'password') {
				const validateCRMPassword = (rule, value, callback) => {
					if (!value || value == '' || regexIsCRMPassword(value)) {
						callback()
					} else {
						callback(
							new Error(
								'密码长度8位以上且至少包含字母、数字或特殊符号中的任意2种'
							)
						)
					}
				}
				tempList.push({
					validator: validateCRMPassword,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'floatnumber') {
				const validateCRMMoneyNumber = (rule, value, callback) => {
					if (!value || value == '' || regexIsCRMMoneyNumber(value)) {
						callback()
					} else {
						callback(new Error('货币的整数部分须少于10位，小数部分须少于2位'))
					}
				}
				tempList.push({
					validator: validateCRMMoneyNumber,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'mobile') {
				const validateCRMMobile = (rule, value, callback) => {
					if (!value || value == '' || regexIsCRMMobile(value)) {
						callback()
					} else {
						callback(new Error('手机格式有误'))
					}
				}
				tempList.push({
					validator: validateCRMMobile,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'email') {
				const validateCRMEmail = (rule, value, callback) => {
					if (value != '' && !regexIsCRMEmail(value)) {
						callback(new Error('邮箱格式有误'))
					} else {
						callback()
					}
				}
				tempList.push({
					validator: validateCRMEmail,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'product') {
				const validateCRMProduct = (rule, value, callback) => {
					if (
						(value && value.product && value.product.length) ||
						item.isNull == 0
					) {
						callback()
					} else {
						callback(new Error('请添加产品'))
					}
				}
				tempList.push({
					validator: validateCRMProduct,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'mince') {
				const validateMince = (rule, value, callback) => {
					if (value?.length || item.isNull == 0) {
						callback()
					} else {
						callback(new Error('请添加' + item.name))
					}
				}
				tempList.push({
					validator: validateMince,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'wangEditor') {
				const validateCRMWangEditor = (rule, value, callback) => {
					if (item.isNull == 1) {
						if (value && value.html) {
						} else {
							callback(new Error('请编辑内容'))
							return
						}
					}
					if (item.isFile == 1) {
						if (value && value.files.length) {
						} else {
							callback(new Error('请上传附件'))
							return
						}
					}
					callback()
				}
				tempList.push({
					validator: validateCRMWangEditor,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'unit') {
				const validateCRMUnit = (rule, value, callback) => {
					if (item.isNull == 0 || value.val) {
						callback()
					} else {
						callback(new Error(item.name + '不能为空'))
					}
				}
				tempList.push({
					validator: validateCRMUnit,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'selectinput') {
				const validateCRMSelectinput = (rule, value, callback) => {
					// if (item.isNull == 0 || value.type) {
					callback()
					// } else {
					// 	callback(new Error(item.name + '不能为空'))
					// }
				}
				tempList.push({
					validator: validateCRMSelectinput,
					item: item,
					trigger: ['change']
				})
			} else if (item.formType == 'address') {
				const validateCRMAddress = (rule, value, callback) => {
					if (item.isNull == 1 && val.filter((v) => v).length === 0) {
						callback(new Error(item.name + '需填写完整'))
						return
					}
					callback()
				}
				tempList.push({
					validator: validateCRMAddress,
					item: item,
					trigger: ['change']
				})
			} else if (
				item.formType == 'businesspersonal' ||
				item.formType == 'customerpersonal' ||
				item.formType == 'relation' ||
				item.formType == 'contractpersonal' ||
				item.formType == 'contacts' ||
				item.formType == 'customer' ||
				item.formType == 'contract' ||
				item.formType == 'business' ||
				item.formType == 'suppliercontacts' ||
				item.formType == 'receivables_plan' ||
				item.formType == 'payable' ||
				item.formType == 'supplier' ||
				item.formType == 'multTreeSelect'
			) {
				const validateCRMRelative = (rule, value, callback) => {
					if (value.length || item.isNull == 0) {
						callback()
					} else {
						callback(new Error(item.name + '不能为空'))
					}
				}
				tempList.push({
					validator: validateCRMRelative,
					item: item,
					trigger: []
				})
			}
			return tempList
		},
		valueChange(data) {
			this.$emit('value-change', data)
			const item = data.item || this.findFieldItem(data.item.key)
			item.value = data.value
			if (item.key === 'coinsurance') {
				console.log('item.value', item.value[0])
			}
			if (
				item.data.formType == 'select' ||
				item.data.formType == 'business_status' ||
				item.data.formType == 'brand'
			) {
				// 选中某些选项值后 可能有追加字段
				const hasLink = item.data.setting.some((option) => option.link)
				if (hasLink) {
					try {
						// 字段删除
						const deItemKeys = item.data.setting
							.map((option) => option.link || [])
							.flat()
							.map((del) => del.fieldName)
						this.delFields(deItemKeys)
						// 字段追加
						let addItems =
							item.data.setting.find((option) => option.value == data.value)
								?.link || [] // 挑出要追加的字段
						addItems = this.useBeforeAddFields(addItems)
						this.insureFields(item.key, addItems)
					} catch (e) {
						console.log(e)
					}
				}

				// 选中某些选项值后 可能有追加字段组
				const hasGroup = item.data.setting.some((option) => option.group)
				if (hasGroup) {
					// 字段组删除
					const deGroupTitles = item.data.setting
						.map((option) => option.group || [])
						.flat()
						.map((group) => group.title)
					this.delGroups(deGroupTitles)
					// // 字段组追加
					let addGorup =
						item.data.setting.find((option) => option.value == data.value)
							?.group || [] // 挑出要追加的字段
					addGorup = this.beforeAddGroup?.(addGorup) || addGorup
					this.pushGroups(addGorup)
				}
			}

			// 是否关联查询其他字段的值
			if (item.data.cascader) {
				setTimeout(() => {
					this.validateField(item.key, (err) => {
						if (!err) {
							item.data.cascader.forEach((ca) => {
								if (typeof ca.props == 'string') {
									ca.props = ca.props.split(',')
								}
								const { fieldName, url, props } = ca
								const cmrFields = this.crmConfigs.map((c) => c.fields).flat()
								const postData = { entity: {}, field: [] }
								for (let prop of props) {
									const element = cmrFields.find((field) => field.key === prop)
									const elParams = this.getSubmiteParams(element)
									postData.entity = Object.assign(
										{},
										postData.entity,
										elParams.entity
									)
									postData.field.push(...elParams.field)
								}
								sendCalenderRequest(url, postData, (res) => {
									this.setFieldValue(fieldName, res.data)
								})
							})
						}
					})
				}, 100)
			}
		},
		useBeforeAddFields(addItems) {
			const { beforeAddFields } = this
			if (typeof beforeAddFields == 'function') {
				return beforeAddFields(addItems)
			}
			return addItems
		},
		resetField(sField) {
			const configs = this.crmConfigs
			for (let index = 0; index < configs.length; index++) {
				const config = configs[index]
				const fIdx = config.fields.findIndex(
					(_field) => _field.key == sField.fieldName
				)

				if (fIdx > -1) {
					const oldFieldSource = config.fields[fIdx].data
					const field = decorateField(Object.assign({}, oldFieldSource, sField))
					console.log('field', field)
					config.fields.splice(fIdx, 1, field)
					break
				}
			}
		},
		/** 拼接上传参数 */
		getSubmiteParams() {
			let params = { entity: {}, field: [], product: [] }
			const cmrFields = this.crmConfigs.map((c) => c.fields).flat()
			for (let index = 0; index < cmrFields.length; index++) {
				const element = cmrFields[index]
				const elParams = this.getFieldParams(element)
				params.entity = Object.assign({}, params.entity, elParams.entity)
				params.field.push(...elParams.field)
				params.product.push(...(elParams.product || []))
			}
			return params
		},
		getFieldParams(element) {
			let params = { entity: {}, field: [] }
			if (
				element.data.formType == 'product' ||
				element.data.formType == 'program' ||
				element.data.formType == 'product-solution'
			) {
				this.getProductParams(params, element)
			} else if (element.data.formType == 'wangEditor') {
				params.entity[element.key] = {
					html: element.value.html
				}
			} else if (
				element.data.formType == 'group' ||
				element.data.formType == 'unit' ||
				element.data.formType == 'selectinput' ||
				element.data.formType == 'check-text'
			) {
				params.entity[element.key] = element.value
			} else if (
				element.data.formType == 'supplier' &&
				element.data.fieldType == 2
			) {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'stageplans') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'tablex') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'channel') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'datagroup') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'datatable') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'data-para') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'multSelect') {
				params.entity[element.key] = element.value
			} else if (element.data.formType == 'multTreeSelect') {
				params.entity[element.key] = element.value.join(',')
			} else if (
				[
					'businesspersonal',
					'contractpersonal',
					'customerpersonal',
					'relation',
					'contacts',
					'customer',
					'contract',
					'business',
					'receivables_plan',
					'suppliercontacts',
					'payable',
					'supplier',
					'person',
					'claim'
				].indexOf(element.data.formType) > -1
			) {
				const key = element.data.primaryKey || element.key // primaryKey 备选relative行中的主键
				if (element.value.length) {
					params.entity[element.key] = element.value
						.map((v) => v[key])
						.join(',')
				} else {
					params.entity[element.key] = ''
				}
			} else if (element.data.formType == 'category') {
				params.entity[element.key] = JSON.stringify(element.value)
			} else if (element.data.fieldType == 1) {
				const key = `${element.key}${element.multiple ? 's' : ''}`
				params.entity[key] = this.getRealParams(element)
			} else if (element.key == 'map_address') {
				this.getCustomerAddressParams(params.entity, element)
			} else {
				element.data.value = this.getRealParams(element)
				params.field.push(element.data)
			}

			return params
		},
		getProductParams(params, element) {
			if (element.value) {
				params['product'] = element.value.product ? element.value.product : []
				params.entity['totalPrice'] = element.value.totalPrice
					? element.value.totalPrice
					: 0
				params.entity['discountRate'] = element.value.discountRate
					? element.value.discountRate
					: 0
			} else {
				params['product'] = []
				params.entity['totalPrice'] = ''
				params.entity['discountRate'] = ''
			}
		},
		// 关联客户 联系人等数据要特殊处理
		getRealParams(element) {
			if (
				element.key == 'customerId' ||
				element.key == 'contactsId' ||
				element.key == 'businessId' ||
				element.key == 'leadsId' ||
				element.key == 'contractId' ||
				element.key == 'payableId' // 应收账款单
			) {
				if (element.value && element.value.length) {
					const key = element.data.primaryKey || element.key
					return element.value.map((v) => v[key]).join(',')
				} else {
					return ''
				}
			} else if (
				element.data.formType == 'user' ||
				element.data.formType == 'structure'
			) {
				return element.value
					.map(function (item, index, array) {
						return element.data.formType == 'user' ? item.userId : item.id
					})
					.join(',')
			} else if (element.data.formType == 'file') {
				if (element.value && element.value.length > 0) {
					switch (element.data.valueType) {
						case 'array':
							return element.value
							break
						default:
							return element.value[0].batchId
					}
				}
				return ''
			} else if (element.key == 'categoryId') {
				if (element.value && element.value.length > 0) {
					return element.value[element.value.length - 1]
				}
				return ''
			} else if (element.data.formType == 'checkbox') {
				if (element.value && element.value.length > 0) {
					return element.value.join(',')
				}
				return ''
			}
			return element.value
		},
		// 查找字段所在的组
		findGroupByField(key) {
			return this.crmConfigs.find((config) => {
				var res = config.fields.find((field) => field.key === key)
				return res
			})
		},
		// 增加字段
		insureFields(key, newFields) {
			const group = this.findGroupByField(key)
			this.crmRules = Object.assign(this.crmRules, this.getRules(newFields))
			const _newFields = newFields.map((f) => (f.key ? f : decorateField(f)))
			group.fields.push(..._newFields)
		},
		// 移除字段
		delFields(keys) {
			keys.forEach((key) => {
				this.crmConfigs.forEach((config) => {
					var currentIdx = config.fields.findIndex((field) => field.key === key)
					var delField = config.fields[currentIdx]
					if (currentIdx > -1) {
						config.fields.splice(currentIdx, 1)
						var { formType } = delField.data
						if (
							formType == 'business_status' ||
							formType == 'select' ||
							formType == 'brand'
						) {
							if (delField.value) {
								const option = delField.data.setting.find(
									(op) => op.value == delField.value
								)
								if (option && option.link) {
									const keys = option.link.map((f) => f.fieldName)
									this.delFields(keys)
								}
							}
						}
					}
				})
			})
		},
		// 移除字段组
		delGroups(titles) {
			titles.forEach((title) => {
				var index = this.crmConfigs.findIndex(
					(config) => config.title === title
				)
				if (index > -1) this.crmConfigs.splice(index, 1)
			})
		},
		// 增加字段组
		pushGroups(groups) {
			groups = groups.map((g) => {
				g.fields = g.source
				return g
			})
			console.log('加入字段组 sources', JSON.parse(JSON.stringify(groups)))
			const configs = this.initConfigs(groups)
			console.log('加入字段组 configs', configs)
			this.delGroups(configs.map((v) => v.title))
			this.crmConfigs.push(...this.initFields(configs))
			this.initRules(configs)
		},
		findFieldItem(key) {
			return this.crmConfigs
				.map((config) => config.fields)
				.flat()
				.find((field) => field.key === key)
		},
		validate(fn) {
			return this.$refs.crmForm.validate().then(() => {
				var params = this.getSubmiteParams()
				fn?.(true, params)
				return params
			})
		},
		validateField(key, callback) {
			this.$refs.crmForm.validateField(key, callback)
		},
		// 获取字段配置
		getField(fieldName) {
			const field = this.crmConfigs
				.map((config) => config.fields)
				.flat()
				.find((field) => field.key === fieldName)
			return field
		},
		setFieldValue(fieldName, value) {
			const field = this.getField(fieldName)
			if (field) {
				this.valueChange({
					item: field,
					value: value
				})
			}
		}
	},
	computed: {
		elFormModel() {
			return this.crmConfigs
				.map((config) => config.fields)
				.flat()
				.reduce((model, field) => {
					model[field.key] = field.value
					return model
				}, {})
		},

		bindStyle() {
			var style = {
				userSelect: 'normal'
			}
			if (this.columnGap) {
				style.columnGap = this.columnGap
			}
			return style
		}
	}
}
</script>

<style lang="scss" scoped="scoped">
.xh-form {
	overflow: hidden;
	padding-bottom: 18px; // 防止错误提示被隐藏

	.xh-title {
		grid-column: 1 / -1;
		font-size: 14px;
		color: #383838;
		font-weight: 600;
		padding: 12px 0 4px;
		&:first-of-type {
			padding-top: 0;
		}
	}
}
.crm-create-box {
	display: grid;
	grid-template-columns: 1fr 1fr;
	column-gap: 15px;
	// justify-items: stretch;
	// align-items: start;
}

.crm-create-item {
	padding: 3px 0;
	box-sizing: border-box;
	// &--half {
	// flex: 0 0 calc(50% - 8px);
	// }
	&--block {
		grid-column: 1 / -1;
	}

	&--mini {
		padding-block: 0;
	}
}

.el-form-item ::v-deep .el-form-item__label {
	line-height: normal;
	font-size: 13px;
	color: #333333;
	position: relative;
	padding-left: 8px;
	padding-bottom: 0;
}

.el-form ::v-deep .el-select {
	width: 100%;
}

.el-form ::v-deep .el-form-item {
	margin-bottom: 0px;
}

.el-form ::v-deep .el-form-item.is-required .el-form-item__label:before {
	content: '*';
	color: #f56c6c;
	margin-right: 4px;
	position: absolute;
	left: 0;
	top: 5px;
}
::v-deep {
	.el-form .el-form-item:not(.is-required) .el-form-item__label:before {
		display: none;
	}
}
</style>
